home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ms_sh21s.zip / SH210 / SRC / SH0.ASM < prev    next >
Assembly Source File  |  1992-12-14  |  30KB  |  1,831 lines

  1.     TITLE   sh0.asm
  2.     NAME    sh0
  3.     .8087
  4.  
  5. ; MS-DOS SHELL - Swapper
  6. ;
  7. ; MS-DOS SHELL - Copyright (c) 1990,1,2 Data Logic Limited
  8. ;
  9. ; This code is subject to the following copyright restrictions:
  10. ;
  11. ; 1.  Redistribution and use in source and binary forms are permitted
  12. ;     provided that the above copyright notice is duplicated in the
  13. ;     source form and the copyright notice in file sh6.c is displayed
  14. ;     on entry to the program.
  15. ;
  16. ; 2.  The sources (or parts thereof) or objects generated from the sources
  17. ;     (or parts of sources) cannot be sold under any circumstances.
  18. ;
  19. ;    $Header: /usr/users/istewart/src/shell/sh2.1/RCS/sh0.asm,v 2.1 1992/07/16 14:33:34 istewart Exp $
  20. ;
  21. ;    $Log: sh0.asm,v $
  22. ;    Revision 2.1  1992/07/16  14:33:34  istewart
  23. ;    Beta 212 Baseline
  24. ;
  25. ;    Revision 2.1  1992/07/16  14:33:34  istewart
  26. ;    Beta 212 Baseline
  27. ;
  28. ;    Revision 2.0  1992/04/13  17:39:45  Ian_Stewartson
  29. ;    MS-Shell 2.0 Baseline release
  30. ;
  31. ;
  32. ;
  33.  
  34. ;
  35. ; Segment declarations
  36. ;
  37.  
  38. SH0_TEXT    segment word public 'CODE'
  39. SH0_TEXT    ends
  40.  
  41. _DATA        segment word public 'DATA'
  42. _DATA        ends
  43.  
  44. CONST        segment word public 'CONST'
  45. CONST        ends
  46.  
  47. _BSS        segment word public 'BSS'
  48. _BSS        ends
  49.  
  50. DGROUP        group    CONST, _BSS, _DATA
  51.  
  52. C_ETEXT        segment word public 'ENDCODE' 
  53. C_ETEXT        ends 
  54.  
  55. ;
  56. ; Declare external functions and data
  57. ;
  58.     extrn    _raise:far
  59.     extrn    __maperror:far
  60.     extrn    _errno:word
  61.     extrn    __psp:word
  62.  
  63. ;
  64. ; Declare end of text variable.  The ENDCODE segment appears to be the last
  65. ; code segment loaded by the Microsoft loader
  66. ;
  67.  
  68. C_ETEXT        segment word public 'ENDCODE' 
  69.         public    cetext
  70. cetext        equ    $
  71. C_ETEXT        ends 
  72.  
  73. ;
  74. ; Start of the spawn function
  75. ;
  76.  
  77. SH0_TEXT    segment
  78.         assume  cs: SH0_TEXT, ds: NOTHING, ss: DGROUP
  79.  
  80. ;
  81. ; For this function, all the code and data space are in the code space
  82. ;
  83.         public    _cmd_line
  84.         public    _path_line
  85.         public    _SW_intr
  86.         public    _SW_Blocks
  87.         public    _SW_SBlocks
  88.         public    _SW_fp
  89.         public    _SW_EMstart
  90.         public    _SW_Mode
  91.         public    _SW_EMSFrame
  92.         public    _SW_Int00
  93.         public    _SW_Int23
  94.         public    _SW_Int24
  95.         public    _SW_XMS_Driver
  96.         public    _SW_XMS_Gversion
  97.         public    _SW_XMS_Allocate
  98.         public    _SW_XMS_Free
  99.         public    _SW_XMS_Available 
  100.         public    _Read_Keyboard
  101.         public    _etext
  102.         public    _SW_Pwrite
  103.         public    _SW_I23_InShell
  104.         public    _SW_poll
  105.  
  106.  
  107. _cmd_line    db    129 dup (?)    ; Command line
  108. _path_line    db    80 dup (?)    ; Path line
  109. _etext        dw    seg cetext    ; End of text segment
  110. _SW_Blocks    dw    0        ; Number of blocks to read/write
  111. _SW_SBlocks    dw    0        ; Short Number of blocks to read/write
  112. _SW_fp        dw    0ffffH        ; File ID
  113. _SW_Pwrite    dw    0        ; Partial write to disk?
  114. _SW_EMstart    dd    0100000H    ; Default Extended Mem start
  115. _SW_Mode    dw    0        ; Type of swapping to do
  116.                     ;   1 - disk
  117.                     ;   2 - Extended memory
  118.                     ;   3 - EMS driver
  119.                     ;   4 - XMS driver
  120. _SW_EMSFrame    dw    0        ; EMS Frame segment
  121. _SW_intr    dw    0        ; Interrupt 23 detected.
  122. _SW_XMS_Driver    dd    0        ; XMS Driver Interface
  123. _SW_I23_InShell    db    0        ; In shell flag for Interrupt 23
  124. _SW_poll    db    0        ; Keyboard polling required
  125.  
  126.  
  127. ;
  128. ; Some addition variables
  129. ;
  130.  
  131. SW_LMstart    dd    0        ; Low Mem start for Extended Mem swap
  132. N_mcb        dw    0        ; Start write address
  133. Result        dw    0        ; Return value
  134.  
  135. ;
  136. ; Stack save pointers
  137. ;
  138.  
  139. S_ss        dw    0            ; Save Stack pointers
  140. S_sp        dw    0
  141. S_di        dw    0            ; Save DI, SI
  142. S_si        dw    0
  143. S_ds        dw    0            ; Save the original DS
  144.  
  145. ;
  146. ; Two blank FCB
  147. ;
  148.  
  149. FCB1        dw    16    dup (?)
  150. FCB2        dw    16    dup (?)
  151.  
  152. ;
  153. ; XMS Driver Move structure
  154. ;
  155.  
  156. XMS_DIF        equ    $
  157. XMS_Length    dd    0            ; Number of bytes
  158. XMS_SHandle    dw    0            ; Source Handler
  159. XMS_Soffset    dd    0            ; Source Offset
  160. XMS_DHandle    dw    0            ; Destination Handler
  161. XMS_Doffset    dd    0            ; Destination Offset
  162.  
  163. ;
  164. ; Extended Memory Global Descriptor tables
  165. ;
  166.         org    XMS_DIF
  167. GD_table    equ    $
  168. GDT_Dummy    dw    4    dup (0)        ; Dummy
  169. GDT_self    dw    4    dup (0)        ; For self
  170. GDT_src        equ    $            ; Source
  171.         dw    04000H            ; Length - 16K bytes
  172. GDT_src_low    dw    0            ;     Low Order address
  173. GDT_src_high    db    0            ;     High Order address
  174.         db    093h            ;     Access Rights
  175.         dw    0            ;     Reserved
  176. GDT_dest    equ    $            ; Destination
  177.         dw    04000H            ;     Length - 16K bytes
  178. GDT_dest_low    dw    0            ;     Low Order address
  179. GDT_dest_high    db    0            ;     High Order address
  180.         db    093h            ;     Access Rights
  181.         dw    0            ;     Reserved
  182. GDT_bios    dw    4    dup (0)        ; Bios
  183. GDT_stack    dw    4    dup (0)        ; Stack
  184.  
  185. ;
  186. ; Execute interrupt structure
  187. ;
  188.  
  189. exec_parms    equ    $
  190. exec_env    dw    0
  191.         dw    offset _cmd_line    ; Command line address
  192. exec_cseg    dw    ?
  193.         dw    offset FCB1        ; FCB1 address
  194. exec_f1seg    dw    ?
  195.         dw    offset FCB2        ; FCB1 address
  196. exec_f2seg    dw    ?
  197.  
  198. Swap_PANIC    db    'PANIC: Swap file re-load error - REBOOT', 0aH, 0dH
  199.         db    '$'
  200.  
  201. Swap_DZERO    db    'PANIC: Divide by zero', 0aH, 0dH
  202.         db    '$'
  203.  
  204. ;
  205. ; OK - exec requires a local stack, cause some programs overwrite it
  206. ;
  207.         even
  208.         db    398 dup (0)
  209. Local_Stack:
  210.         dw    0
  211.  
  212. ;
  213. ; Code starts
  214. ;
  215.     public    _SA_spawn
  216.  
  217. SA_spawn1    proc    far
  218.     mov    ds, word ptr cs:exec_env    ; Load Env seg.
  219.     xor    si, si                ; Clear start offset
  220.  
  221. ;
  222. ; Copy into Env Seg
  223. ;
  224.  
  225. $Copy_Env:
  226.     les    bx, dword ptr ss:[bp + 6]    ; Check for end of loop
  227.     mov    ax, word ptr es:[bx + 0]
  228.     or    ax, word ptr es:[bx + 2]
  229.     je    $Copy_End
  230.  
  231. ;
  232. ; Save start address
  233. ;
  234.     add    word ptr ss:[bp + 6], 4        ; Increment environment by 4
  235.  
  236.     mov    cx, word ptr es:[bx + 0]    ; Load address of cur Env string
  237.     mov    ax, word ptr es:[bx + 2]    ; into es:bx
  238.     mov    es, ax
  239.     mov    bx, cx
  240.  
  241. ;
  242. ; Copy this value
  243. ;
  244.  
  245. $Copy_Val:
  246.     mov    al, byte ptr es:[bx]    ; Copy across
  247.     mov    byte ptr ds:[si], al
  248.     inc    bx            ; Increment pointers
  249.     inc    si
  250.     or    al, al
  251.     jne    $Copy_Val
  252.     jmp    $Copy_Env
  253.  
  254. ;
  255. ; Set up exec parameter block     - DS is on stack
  256. ;
  257. $Copy_End:
  258.     xor    ax, ax
  259.     mov    word ptr ds:[si], ax    ; Terminate environment
  260.     add    si, 2
  261.  
  262. ;
  263. ; Set up new program length
  264. ;
  265.     add    si, 16            ; Round up paras
  266.     mov    dx, si            ; Save end offset in DX
  267.     mov    bx, ds
  268.  
  269.     mov    cl, 4
  270.     shr    si, cl            ; # paras used by Env
  271.     add    si, bx            ; End para number
  272.  
  273.     mov    bx, word ptr cs:N_mcb    ; Load our MCB address in BX
  274.     mov    ax, bx
  275.     inc    ax
  276.     sub    si, ax
  277.     mov    cx, si            ; Save new max paras in CX
  278.  
  279. ;
  280. ; Use interrupt 4a to shrink memory.  First release all memory above us.
  281. ;
  282.     push    ax
  283.     push    cx            ; Save Max paras and location
  284.     mov    ds, bx            ; Set up the segement for MCB
  285.     mov    cx, word ptr ds:3    ; Get the MCB length
  286.  
  287. ; Are we the only one in the chain?
  288.  
  289.     cmp    byte ptr ds:0, 'Z'    ; End of chain ?
  290.     jz    $Shrink_First
  291.  
  292. ;
  293. ; Loop round releasing memory blocks
  294. ;
  295. ;    CX - original length of block;
  296. ;    DS - segement of the previous block
  297. ;
  298. $Shrink_Next:
  299.     mov    ax, ds            ; Move to the next block
  300.     add    cx, ax
  301.     inc    cx
  302.     mov    ds, cx
  303.  
  304.     cmp    byte ptr ds:0, 'Z'    ; End of chain ?
  305.     jz    $Shrink_First
  306.  
  307.     mov    cx, word ptr ds:3    ; Save the length of this block
  308.  
  309.     mov    ax, ds            ; Advance to the block itself
  310.     inc    ax
  311.     mov    es, ax            ; Set up Block address
  312.  
  313.     mov    ah, 049H
  314.     int    021H
  315.     jmp    $Shrink_Next
  316.  
  317. ;
  318. ;    Shrink the PSP segment
  319. ;
  320.  
  321. $Shrink_First:
  322.     pop    cx
  323.     pop    ax
  324.         mov    es, ax            ; Set PSP address
  325.     mov    bx, cx            ; Set max length
  326.     mov    ah, 04aH
  327.     int    021H
  328.  
  329. ;
  330. ; Execute function
  331. ;
  332.  
  333.     mov    word ptr cs: S_sp, sp    ; Save the current stack
  334.     mov    word ptr cs: S_ss, ss
  335.  
  336. ;
  337. ; Move to the local stack so that it doesn't get overwritten.
  338. ;
  339.     mov    ax, cs
  340.     cli
  341.     mov    sp, offset Local_Stack
  342.     mov    ss, ax
  343.     sti
  344.  
  345. ; Clear out Interrupts
  346.  
  347.     mov    ah, 00bH        ; Check Keyboard status
  348.     int    021H
  349.  
  350. ;
  351. ;  Check for interrupt 23 detected
  352. ;
  353.     mov    ax, word ptr cs:_SW_intr
  354.     or    ax, ax
  355.     jz    $I23_Cf            ; No - continue;
  356.  
  357. ;
  358. ; Interrupt 23 detected - abort
  359. ;
  360.     mov    ax, cs            ; Set up for reload
  361.     cli
  362.     mov    sp, offset Local_Stack
  363.     mov    ss, ax
  364.     sti
  365.  
  366.     mov    ds, word ptr cs:S_ds    ; Restore DS
  367.     xor    ax, ax
  368.     jmp    $Exec_Complete
  369.  
  370. ;
  371. ; No interrupts - continue
  372. ;
  373. $I23_Cf:
  374.     mov    ax, cs            ; Set up segments
  375.     mov    es, ax
  376.     mov    ds, ax
  377.  
  378.     mov    ax, 04b00H        ; Load and execute function
  379.     mov    dx, offset _path_line    ; Load path
  380.     mov    bx, offset exec_parms    ; Load the execute structure
  381.     mov    byte ptr cs:_SW_I23_InShell, 1    ; Set not shell flag 
  382.     int    021H
  383.     mov    byte ptr cs:_SW_I23_InShell, 0    ; Set in shell flag 
  384.  
  385. ; Disable interrupts while we restore the stack to the local one
  386.  
  387.     mov    ax, cs
  388.     cli
  389.     mov    sp, offset Local_Stack
  390.     mov    ss, ax
  391.     sti
  392.  
  393. ;
  394. ; Did an error occur?
  395. ;
  396.     jnc    $Exec_OK
  397.  
  398. ;
  399. ; Error
  400. ;
  401.  
  402. $Map_error:
  403.     mov    ds, word ptr cs:S_ds    ; Restore DS
  404.     mov    ah, al
  405.     call    far ptr __maperror    ; Map the error
  406.  
  407. $Exec_Error:
  408.     mov    ax, 0FFFFH
  409.     jmp    $Exec_Complete
  410.  
  411. ;
  412. ; No - get the exit code and check for interrupts
  413. ;
  414.  
  415. $Exec_OK:
  416.     mov    ax, 04d00H
  417.     int    021H
  418.     dec    ah            ; Interrupt termination ?
  419.     jnz    $Exec_OK1
  420.  
  421.     inc    word ptr ds:_SW_intr    ; Set Interrupt 23 detected.
  422.  
  423. $Exec_OK1:
  424.     xor    ah, ah
  425.  
  426. ;
  427. ; Save the result code
  428. ;
  429.  
  430. $Exec_Complete:
  431.     mov    word ptr cs:Result, ax        ; Save response
  432.  
  433. ;
  434. ; Very Dangerous - Restore Environment
  435. ;
  436. ;     Seek to 0x4000 in file
  437. ;
  438.     mov    bx, word ptr cs:_SW_fp        ; Load File Handler
  439.     mov    ax, word ptr cs: _SW_Mode    ; Skip if not disk
  440.     dec    ax
  441.     jnz    $Seek_OK
  442.  
  443. ; Seek in file to skip 16K
  444.  
  445.     mov    dx, 04000H
  446.     call    $Seek_Disk
  447.  
  448. ;
  449. ;     Load from N_mcb:0x4000 to end of file.
  450. ;
  451.  
  452. $Seek_OK:
  453.     mov    si, word ptr cs:_SW_Blocks    ; Load number of transfers
  454.     dec    si                ; Skip first block
  455.  
  456. ;
  457. ; set up ES register with start of load
  458. ;
  459.     mov    ax, word ptr cs:N_mcb    ; Load the start address
  460.     add    ax, 0400H
  461.     mov    ds, ax
  462.  
  463. ; load up extended memory GDT for destination
  464.  
  465.     call    $GDT_reload
  466.     call    $Inc_Extend            ; Increment addresses by 16K
  467.  
  468. ;
  469. ; Check for end of copy    - BX - File Handler for disk
  470. ;
  471.  
  472. $Read_loop:
  473.     or    si, si
  474.     je    $Read_Complete
  475.  
  476. ; OK - Copy next 0x4000 bytes - switch on device
  477.  
  478.     mov    ax, word ptr cs: _SW_Mode
  479.     dec    ax
  480.     jz    $R_disk
  481.     dec    ax
  482.     jz    $R_extend
  483.     dec    ax
  484.     jz    $R_expand
  485.  
  486. ;
  487. ; Read from XMS driver.  In this case, we do one read and let the driver
  488. ; sort out the blocking
  489. ;
  490.     call    $Read_XMS
  491.     jmp     $Read_Complete
  492.  
  493. ; Read from disk
  494.  
  495. $R_disk:
  496.     call    $Read_disk
  497.     jmp    $Read_loop
  498.  
  499. ; Read from extended memory
  500.  
  501. $R_extend:
  502.     call    $Read_extend
  503.     jmp    $Read_loop
  504.  
  505. ; Read from expanded memory
  506.  
  507. $R_expand:
  508.     call    $Read_EMS
  509.     jmp    $Read_loop
  510.  
  511. ;
  512. ; Re-load is now complete, Restore original stack which has just been
  513. ; reloaded.  BX contains FP
  514. ;
  515.  
  516. $Read_Complete:
  517.     cli
  518.     mov    sp, word ptr cs: S_sp        ; Save the current stack
  519.     mov    ss, word ptr cs: S_ss
  520.     sti
  521.  
  522. ;  Save exit code
  523.  
  524.     push    word ptr cs:Result        ; Save response
  525.     push    word ptr cs:_SW_intr        ; and interrupt flag
  526.  
  527. ;
  528. ; Read in the first block - BX - File Handler
  529. ;
  530.  
  531.     mov    ax, word ptr cs: _SW_Mode    ; Skip if not disk
  532.     dec    ax
  533.     jnz    $Seek1_OK
  534.  
  535. ; Seek to 0 in file
  536.  
  537.     xor    dx, dx
  538.     call    $Seek_Disk
  539.  
  540. ;
  541. ;     Load one block at N_mcb:0x0000
  542. ;
  543. $Seek1_OK:
  544.     mov    ds, word ptr cs:N_mcb        ; Load the start address
  545.     call    $GDT_reload            ; Load the GDT for extend mem
  546.  
  547.     mov    ax, word ptr cs: _SW_Mode    ; Skip if not disk
  548.     dec    ax
  549.     jz    $R1_Disk
  550.     dec    ax
  551.     jz    $R1_Extend
  552.     dec    ax
  553.     jz    $R1_Expand
  554.  
  555.     mov    si, 1                ; Read one block
  556.     call    $Read_XMS
  557.     jmp    $Read1_OK
  558.  
  559. $R1_Disk:
  560.     call    $Read_disk
  561.     jmp    $Read1_OK
  562.  
  563. $R1_Extend:
  564.     call    $Read_extend
  565.     jmp    $Read1_OK
  566.  
  567. $R1_Expand:
  568.     mov    si, word ptr cs:_SW_Blocks    ; Read first block
  569.     call    $Read_EMS
  570.  
  571. ;
  572. ; Complete - load error code and return
  573. ;
  574.  
  575. $Read1_OK:
  576.     pop    word ptr cs:_SW_intr        ; Restore interrupt flag
  577.     pop    ax
  578.  
  579. ;
  580. ; Exit function - Restore Control Interrupt handler
  581. ;
  582.  
  583. $SA_spawn_Exit:
  584.  
  585.     mov    di, word ptr cs:S_di        ; Restore saved registers
  586.     mov    si, word ptr cs:S_si
  587.     mov    ds, word ptr cs:S_ds
  588.  
  589.     mov    sp, bp
  590.     pop    bp
  591.     ret
  592.  
  593. SA_spawn1    endp
  594.  
  595. ;
  596. ; READ XMS DRIVER FUNCTION
  597. ;
  598. ;    BX - file handler
  599. ;    SI - Block count
  600. ;    DS - Output data segement
  601. ;
  602. $Read_XMS    proc    near
  603.     xor    ax, ax
  604.     mov    word ptr cs:XMS_SHandle, bx    ; Source - XMS
  605.     mov    word ptr cs:XMS_DHandle, ax    ; Dest - normal memory
  606.  
  607.     mov    word ptr cs:XMS_Soffset, ax    ; Source offset - zero
  608.     mov    word ptr cs:XMS_Soffset + 2, ax
  609.  
  610.     mov    word ptr cs:XMS_Doffset, ax    ; Dest offset DS:0
  611.     mov    ax, ds
  612.     mov    word ptr cs:XMS_Doffset + 2, ax
  613.  
  614.     cmp    si, 1                ; If first block, the
  615.     jz    $Read_X1            ; source offset is
  616.                         ; 4000H
  617.     mov    word ptr cs:XMS_Soffset, 04000H
  618.  
  619. ;
  620. ; Set up number of bytes: si * 16 * 1024
  621. ;
  622.  
  623. $Read_X1:
  624.     mov    ax, si
  625.     mov    dx, si
  626.     mov    cl, 14
  627.     shl    ax, cl
  628.     mov    cl, 2
  629.     shr    dx, cl
  630.     mov    word ptr cs:XMS_Length, ax    ; Load number of bytes
  631.     mov    word ptr cs:XMS_Length + 2, dx
  632.  
  633.     mov    ah, 0BH                ; Set up parameters
  634.     mov    dx, cs
  635.     mov    ds, dx
  636.     mov    si, offset XMS_DIF
  637.     call    cs:[_SW_XMS_Driver]
  638.     or    ax, ax
  639.     jnz     $Read_XMS1
  640.     jmp    Load_Error            ; XMS error - abort
  641.  
  642. $Read_XMS1:
  643.     ret
  644.  
  645. $Read_XMS    endp
  646.  
  647. ;
  648. ; READ DISK FUNCTION
  649. ;
  650. ;    BX - file handler
  651. ;    SI - Block count
  652. ;    DS - Output data segement
  653. ;
  654.  
  655. $Read_disk    proc    near
  656.  
  657.     mov    ax, 03f00H        ; Set up to read
  658.     mov    cx, 04000H        ; Load count
  659.     xor    dx, dx            ; Clear start address
  660.  
  661.     int    021H            ; Read the data
  662.  
  663.     jnc    $Read_OK        ; NO - abort
  664.     jmp    Load_Error        ; Abort - swap file error
  665.  
  666. ;
  667. ; Read OK - next block
  668. ;
  669.  
  670. $Read_OK:
  671.     dec    si            ; Decrement block count
  672.     mov    ax, ds            ; Increment offset
  673.     add    ax, 0400H
  674.     mov    ds, ax
  675.     ret
  676.  
  677. $Read_disk    endp
  678.  
  679. ;
  680. ; READ EMS FUNCTION
  681. ;
  682. ;    BX - file handler
  683. ;    SI - Block count - counts from max
  684. ;    DS - Output data segement
  685. ;
  686.  
  687. $Read_EMS    proc    near
  688.  
  689.     call    $map_ems_page        ; Map in the current EMS page
  690.     jnz    Load_Error
  691.  
  692.     push    ds            ; Save DS and SI
  693.     push    si
  694.     mov    ax, ds
  695.     mov    es, ax
  696.     mov    ds, word ptr cs:_SW_EMSFrame    ; Set Dest Seg
  697.     xor    si, si            ; Clear start
  698.     xor    di, di
  699.     mov    cx, 02000H        ; move 16K
  700.     pushf                ; Save direction flag
  701.     cld
  702.     rep movsw
  703.     popf                ; Restore direction flag
  704.     pop    si            ; And DS, SI
  705.     pop    ds
  706.     jmp    $Read_OK        ; Increment DS and dec SI
  707.  
  708. $Read_EMS    endp
  709.  
  710. ;
  711. ; MAP IN THE CURRENT EMS PAGE
  712. ;
  713. ;    BX - file handler
  714. ;    SI - Block count - counts from max
  715. ;    DS - Output data segement
  716. ;
  717.  
  718. $map_ems_page    proc    near
  719.  
  720.     push    bx            ; Need to save BX
  721.     mov    ax, 04400h        ; Map into physical page zero
  722.     mov    dx, bx            ; Set up handler
  723.     mov    bx, word ptr cs: _SW_Blocks
  724.     sub    bx, si
  725.  
  726.     int    067H
  727.     pop    bx
  728.  
  729.     or    ah, ah
  730.     ret
  731.  
  732. $map_ems_page    endp
  733.  
  734. ;
  735. ; DISK SEEK FUNCTION
  736. ;
  737. ;    BX - file handler
  738. ;    DX - offset
  739. ;
  740. $Seek_Disk    proc    near
  741.  
  742.     mov    ax, 04200H        ; Set seek
  743.     xor    cx, cx
  744.     int    021H
  745.     jc    Load_Error        ; Abort - swap file error
  746.     ret
  747.  
  748. $Seek_Disk    endp
  749.  
  750. ;
  751. ; PANIC - Abort
  752. ;
  753.  
  754. Load_Error    proc    near
  755.  
  756.     mov    di, offset Swap_PANIC
  757.     mov    bx, cs
  758.     mov    ds, bx
  759.     call    I24_Display
  760. $Wait_L:
  761.     sti
  762.     hlt
  763.     jmp    $Wait_L
  764.  
  765. Load_Error    endp
  766.  
  767. ;
  768. ;  WRITE EXTENDED MEMORY
  769. ;
  770. ;    SI - Block count
  771. ;
  772. $Write_extend    proc    near
  773.  
  774.     push    si            ; Save SI (block counter)
  775.     mov    cx, 02000H        ; Copy a 16K block
  776.     mov    ax, cs            ; Set up GDT address
  777.     mov    es, ax
  778.     mov    si, offset GD_table
  779.  
  780.     mov    ah, 087H        ; EMS function
  781.     int    015H
  782.     pop    si
  783.     ret
  784.  
  785. $Write_extend    endp
  786.  
  787. ;
  788. ;  READ FROM EXTENDED MEMORY
  789. ;
  790. ;    SI - Block count
  791. ;
  792.  
  793. $Read_extend    proc    near
  794.  
  795.     call    $Write_extend
  796.     jc    Load_Error        ; NO - abort
  797.  
  798.     dec    si            ; Decrement block count
  799.  
  800. $Read_extend    endp
  801.  
  802. ;
  803. ; INCREMENT Extended MEMORY GDT
  804. ;
  805. ;    AX - used
  806. ;
  807. $Inc_Extend    proc    near
  808.  
  809.     mov    ax, 04000H        ; Increment address by 16K
  810.     add    word ptr cs:GDT_dest_low, ax
  811.     adc    byte ptr cs:GDT_dest_high, 0
  812.     add    word ptr cs:GDT_src_low, ax
  813.     adc    byte ptr cs:GDT_src_high, 0
  814.     ret
  815.  
  816. $Inc_Extend    endp
  817.  
  818. ;
  819. ; LOAD SOURCE GDT ADDRESS
  820. ;
  821. ;    AX - low order
  822. ;    DL - high order
  823. ;
  824. $GDT_src_load    proc    near
  825.  
  826.  
  827.     mov    word ptr cs:GDT_src_low, ax
  828.     mov    byte ptr cs:GDT_src_high, dl
  829.     ret
  830.  
  831. $GDT_src_load    endp
  832.  
  833. ;
  834. ; LOAD DESTINATION GDT ADDRESS
  835. ;
  836. ;    AX - low order
  837. ;    DL - high order
  838. ;
  839. $GDT_dest_load    proc    near
  840.  
  841.     mov    word ptr cs:GDT_dest_low, ax
  842.     mov    byte ptr cs:GDT_dest_high, dl
  843.     ret
  844.  
  845. $GDT_dest_load    endp
  846.  
  847. ;
  848. ; LOAD the GDT for reloading
  849. ;
  850.  
  851. $GDT_reload    proc    near
  852.     mov    ax, word ptr cs:_SW_EMstart     ; Load Full start address
  853.     mov    dl, byte ptr cs:_SW_EMstart + 2
  854.     call    $GDT_src_load
  855.  
  856.     mov    ax, word ptr cs:SW_LMstart     ; Load Full start address
  857.     mov    dl, byte ptr cs:SW_LMstart + 2
  858.     call    $GDT_dest_load
  859.     ret
  860. $GDT_reload    endp
  861.  
  862. ;
  863. ; CONTROL C INTERRUPT HANDLER - IGNORE
  864. ;
  865.  
  866. _SW_Int23    proc    far
  867.     inc    word ptr cs:_SW_intr    ; Set Interrupt 23 detected.
  868.     cmp    byte ptr cs:_SW_I23_InShell, 0    ; are we in the shell?
  869.     jz    $SA_Ins
  870.  
  871. ; In another program - move the stack around
  872.  
  873.     stc
  874.     ret
  875.  
  876.  
  877. ; In shell - ignore interrupt 23 for the moment
  878.  
  879. $SA_Ins:
  880.     iret
  881.  
  882. _SW_Int23    endp
  883.  
  884. ;
  885. ; DIVIDE BY ZERO INTERRUPT HANDLER - Output message
  886. ;
  887.  
  888. _SW_Int00    proc    far
  889.  
  890.     mov    ax, 00900H
  891.     mov    dx, offset Swap_DZERO
  892.     mov    bx, cs
  893.     mov    ds, bx
  894.     int    021H
  895.  
  896.     mov    ax, 04CFFh        ; Exit
  897.     int    021H
  898.  
  899. _SW_Int00    endp
  900.  
  901. ;
  902. ; INTERRUPT 24 - ERROR HANDLER - Output message
  903. ;
  904. ;    AH - Bit  7    = 0 Disk error
  905. ;            = 1 FAT error if block device
  906. ;                Error code in DI if character device
  907. ;      Bit  6    UNUSED
  908. ;      Bit  5    = 1 Ignore allowed
  909. ;      Bit  4    = 1 Retry allowed
  910. ;      Bit  3    = 1 Fail allowed
  911. ;      Bits 2 & 1    = Disk Area
  912. ;      Bit  0    = 1 Writing error
  913. ;    AL         = Disk drive number
  914. ;    DI            = Error code
  915. ;    BP:SI        = Header of device driver for which error occured
  916. ;
  917. ;
  918. ; Return
  919. ;    AL            = 0 Ignore Error
  920. ;            = 1 Retry operation
  921. ;            = 2 Abort program
  922. ;            = 3 Fail system call
  923. ;
  924.  
  925. I24_Errors    equ    $
  926. I24_EC00:    db    'Write-protect error$'
  927. I24_EC01:    db    'Unknown unit$'
  928. I24_EC02:    db    'Drive not ready$'
  929. I24_EC03:    db    'Unknown command$'
  930. I24_EC04:    db    'CRC error$'
  931. I24_EC05:    db    'Bad request structure length$'
  932. I24_EC06:    db    'Seek error$'
  933. I24_EC07:    db    'Unknown media type$'
  934. I24_EC08:    db    'Sector not found$'
  935. I24_EC09:    db    'Out of paper$'
  936. I24_EC0A:    db    'Write fault$'
  937. I24_EC0B:    db    'Read fault$'
  938. I24_EC0C:    db    'General failure$'
  939. I24_EC0D:    db    'Sharing violation$'
  940. I24_EC0E:    db    'Lock violation$'
  941. I24_EC0F:    db    'Invalid disk change$'
  942. I24_EC10:    db    'FCB unavailable$'
  943. I24_EC11:    db    'Sharing buffer overflow$'
  944. I24_ECUK:    db    'Unknown error$'
  945.  
  946. ;
  947. ; Error message address table
  948. ;
  949.  
  950. I24_ECTABLE:    dw    offset I24_EC00
  951.         dw    offset I24_EC01
  952.         dw    offset I24_EC02
  953.         dw    offset I24_EC03
  954.         dw    offset I24_EC04
  955.         dw    offset I24_EC05
  956.         dw    offset I24_EC06
  957.         dw    offset I24_EC07
  958.         dw    offset I24_EC08
  959.         dw    offset I24_EC09
  960.         dw    offset I24_EC0A
  961.         dw    offset I24_EC0B
  962.         dw    offset I24_EC0C
  963.         dw    offset I24_EC0D
  964.         dw    offset I24_EC0E
  965.         dw    offset I24_EC0F
  966.         dw    offset I24_EC10
  967.         dw    offset I24_EC11
  968.         dw    offset I24_ECUK
  969.  
  970. I24_ECON:    db    ' when $'
  971. I24_ECREAD:    db    'reading $'
  972. I24_ECWRITE:    db    'writing $'
  973. I24_ECDEVICE:    db    'device $'
  974. I24_ECDISK:    db    'disk $'
  975. I24_EABORT:    db    'Abort$'
  976. I24_EFAIL:    db    ', Fail$'
  977. I24_EIGNORE:    db    ', Ignore$'
  978. I24_ERETRY:    db    ', Retry$'
  979. I24_EDRIVE:    db    '?:$'
  980. I24_EQUESTION    db    '? $'
  981. I24_RESPONSE:    db    ' '
  982. I24_ENL:    db    0dH, 0aH, '$'
  983. I24_EBELL:    db    07H, '$'
  984. I24_EDNAME:    db    '12345678:$'
  985. I24_EXTECODE:    db    0dH, 0aH, '(Extended Code: '
  986. I24_E_AL:    db    '  h'
  987.         db    ' Class: '
  988. I24_E_BH:    db    '  h'
  989.         db    ' Action: '
  990. I24_E_BL:    db    '  h'
  991.         db    ' Locus: '
  992. I24_E_CH:    db    '  h)', 0dH, 0aH, '$'
  993.  
  994. ;
  995. ; Save DS, ES, BX, CX, DX
  996. ;
  997. _SW_Int24    proc    far
  998.     push    ds        ; Save registers
  999.     push    es
  1000.     push    bx
  1001.     push    cx
  1002.     push    dx
  1003.  
  1004.     push    cs        ; Set up data segment
  1005.     pop    ds
  1006.  
  1007.     mov    cx, ax        ; Save the error information in CX
  1008.  
  1009.     mov    di, offset I24_ENL
  1010.     call    I24_Display
  1011. ;
  1012. ; Get extended error codes
  1013. ;
  1014.     push    cx
  1015.     push    ds
  1016.     push    si
  1017.     push    bp
  1018.     mov    ah, 059H
  1019.     xor    bx, bx
  1020.     int    021H
  1021.     pop    bp
  1022.     pop    si
  1023.     pop     ds
  1024.     pop    cx
  1025.     sub    ax, 13H
  1026.     mov    di, ax
  1027.  
  1028. ;
  1029. ;  Check inside message range
  1030. ;
  1031.     cmp    di, 012H
  1032.     jb    SWI24a
  1033.     mov    di, 12H        ;new 'unknown error' entry
  1034.  
  1035. ;
  1036. ; Write the error message
  1037. ;
  1038.  
  1039. SWI24a:
  1040.     add    di, di
  1041.  
  1042.     mov    di, word ptr ds:I24_ECTABLE[di]
  1043.     call    I24_Display
  1044.  
  1045. ;
  1046. ; Output on message
  1047. ;
  1048.  
  1049.     mov    di, offset I24_ECON
  1050.     call    I24_Display
  1051.  
  1052. ;
  1053. ; Output reading or write message
  1054. ;
  1055.  
  1056.     mov    di, offset I24_ECWRITE
  1057.     test    ch, 01H
  1058.     jnz    SWI24b
  1059.     mov    di, offset I24_ECREAD
  1060.  
  1061. SWI24b:
  1062.     call    I24_Display
  1063.  
  1064. ;
  1065. ; Output device message
  1066. ;
  1067.  
  1068.     test    ch, 080H
  1069.     jz    SWI24c
  1070.  
  1071.     mov    di, offset I24_ECDEVICE
  1072.     call    I24_Display
  1073.  
  1074. ;
  1075. ; Output device name - up to eight characters
  1076. ;
  1077.  
  1078.     add    si, 0aH            ; Move to device name
  1079.     push    ds
  1080.     mov    ds, bp
  1081.     xor    di, di            ; Set counter
  1082.  
  1083. SWI24b1:
  1084.     mov    dl, byte ptr ds:[si]    ; Get next character in name
  1085.     cmp    dl, ' '
  1086.     jz    SWI24d
  1087.  
  1088.     mov    byte ptr cs:[I24_EDNAME + di], dl
  1089.  
  1090.     inc    si
  1091.     inc    di
  1092.     cmp    di, 8
  1093.     jnz    SWI24b1
  1094. ;
  1095. ; Append a : and $
  1096. SWI24d:
  1097.     pop    ds
  1098.     mov    byte ptr cs:[I24_EDNAME + di], ':'
  1099.     mov    byte ptr cs:[I24_EDNAME + 1 + di], '$'
  1100.     mov    di, offset I24_EDNAME
  1101.     jmp    SWI24e
  1102.  
  1103. ;
  1104. ; Write disk error
  1105. ;
  1106. SWI24c:
  1107.     mov    di, offset I24_ECDISK
  1108.     call    I24_Display
  1109.  
  1110.     mov    dl, cl
  1111.     add    dl, 'A'
  1112.     mov    byte ptr cs:I24_EDRIVE, dl
  1113.  
  1114.     mov    di, offset I24_EDRIVE
  1115. SWI24e:
  1116.     call    I24_Display
  1117.  
  1118. ;
  1119. ; Get extended error codes
  1120. ;
  1121.     push    cx
  1122.     push    ds
  1123.     mov    ah, 059H
  1124.     xor    bx, bx
  1125.     int    021H
  1126.  
  1127. ;
  1128. ; Save responses
  1129. ;
  1130.  
  1131.     mov    byte ptr cs:I24_E_AL, al
  1132.     mov    byte ptr cs:I24_E_BL, bl
  1133.     mov    byte ptr cs:I24_E_BH, bh
  1134.     mov    byte ptr cs:I24_E_CH, ch
  1135.     pop    ds
  1136.     pop    cx
  1137.  
  1138. ; Convert to display Hex.
  1139.  
  1140.     mov    di, offset I24_E_AL
  1141.     call    I24_Convert
  1142.     mov    di, offset I24_E_BL
  1143.     call    I24_Convert
  1144.     mov    di, offset I24_E_BH
  1145.     call    I24_Convert
  1146.     mov    di, offset I24_E_CH
  1147.     call    I24_Convert
  1148.     mov    di, offset I24_EXTECODE
  1149.     call    I24_Display
  1150. ;
  1151. ; Output Options 
  1152. ;
  1153.     mov    di, offset I24_EABORT
  1154.     call    I24_Display
  1155.  
  1156.     test    ch, 020H        ; Ignore allowed ?
  1157.     jz    SWI24f
  1158.     mov    di, offset I24_EIGNORE
  1159.     call    I24_Display
  1160.  
  1161. SWI24f:
  1162.     test    ch, 010H        ; Retry allowed ?
  1163.     jz    SWI24g
  1164.     mov    di, offset I24_ERETRY
  1165.     call    I24_Display
  1166.  
  1167. SWI24g:
  1168.     test    ch, 08H            ; Fail allowed ?
  1169.     jz    SWI24h
  1170.     mov    di, offset I24_EFAIL
  1171.     call    I24_Display
  1172.  
  1173. ;
  1174. ; Append a question mark.
  1175. ;
  1176.  
  1177. SWI24h:
  1178.     mov    di, offset I24_EQUESTION
  1179.     call    I24_Display
  1180.  
  1181. ;
  1182. ; Get the valid key codes
  1183. ;
  1184. SWI24j:
  1185.     xor    ax, ax            ; Read a keyboard character
  1186.     int    16H
  1187.     and    al, 05fH        ; Upper case
  1188.  
  1189.     xor    ah, ah            ; Clear counter
  1190.     cmp    al, 'I'            ; Ignore ?
  1191.     jnz    SWI24k
  1192.     test    ch, 020H
  1193.     jnz    SWI24n
  1194. SWI24k:
  1195.     inc    ah
  1196.     cmp    al, 'R'            ; Retry ?
  1197.     jnz    SWI24l
  1198.     test    ch, 010H
  1199.     jnz    SWI24n
  1200. SWI24l:
  1201.     inc    ah
  1202.     cmp    al, 'A'            ; Abort ?
  1203.     jz    SWI24n
  1204.  
  1205.     inc    ah
  1206.     cmp    al, 'F'            ; Fail ?
  1207.     jnz    SWI24m
  1208.     test    ch, 08H
  1209.     jnz    SWI24n
  1210. SWI24m:
  1211.     mov    di, offset I24_EBELL
  1212.     call    I24_Display
  1213.     jmp    SWI24j
  1214.  
  1215. ;
  1216. ; OK - got code
  1217. ;
  1218. SWI24n:
  1219.     mov    cl, ah
  1220.     mov    byte ptr ds:I24_RESPONSE, al
  1221.     mov    di, offset I24_RESPONSE
  1222.     call    I24_Display
  1223.     mov    ax, cx
  1224.  
  1225. ;
  1226. ; Are we in the shell ?
  1227. ;
  1228.     cmp    byte ptr cs:_SW_I23_InShell, 0    ; Are we in the shell ? 
  1229.     jnz    $SW_int24a        ; No - no processing
  1230.  
  1231.     cmp    al, 02H            ; Abort?
  1232.     jnz    $SW_int24a        ; No - exit
  1233.  
  1234.     test    ah, 008h        ; If fail allowed - convert to fail
  1235.     jz    $SW_int24a
  1236.  
  1237.     mov    al, 003h        ; Fail system call
  1238.  
  1239. $SW_int24a:
  1240.     pop    dx            ; Restore registers
  1241.     pop    cx
  1242.     pop    bx
  1243.     pop    es
  1244.     pop    ds        
  1245.     iret
  1246. _SW_Int24    endp
  1247.  
  1248. ;
  1249. ; Convert Hex code to display code
  1250. ;
  1251. ; ds:di Offset of code to replace
  1252. ; ax is available
  1253. ;
  1254. I24_Convert    proc    near
  1255.     push    cx
  1256.     mov    al, byte ptr ds:[di]    ; Get the code
  1257.     mov    ah, al
  1258.     mov    cl, 4
  1259.     shr    ah, cl
  1260.     and    ah, 0fh
  1261.  
  1262.     cmp    ah, 10
  1263.     jb    I24_C1
  1264.     add    ah, 'A' - 10
  1265.     jmp    I24_C2
  1266. I24_C1:
  1267.     add    ah, '0'
  1268. I24_C2:
  1269.     mov    byte ptr ds:[di], ah
  1270.  
  1271. ; Now LSB
  1272.  
  1273.     and    al, 0fh
  1274.     cmp    al, 10
  1275.     jb    I24_C3
  1276.     add    al, 'A' - 10
  1277.     jmp    I24_C4
  1278. I24_C3:
  1279.     add    al, '0'
  1280. I24_C4:
  1281.     mov    byte ptr ds:[di + 1], al
  1282.     pop    cx
  1283.     ret
  1284. I24_Convert    endp
  1285. ;
  1286. ;  Display message function for Interrupt 24 processing
  1287. ;
  1288. ;  DS:DI message
  1289. ;  AX is available
  1290. ;
  1291.  
  1292. I24_Display    proc    near
  1293.     mov    ah, 08H            ; Get foreground colour
  1294.     xor    bx, bx
  1295.     int    10H
  1296.     mov    bl, ah
  1297.     and    bl, 07h
  1298.  
  1299. ;
  1300. ; Loop until a $ is hit, outputting the characters
  1301. ;
  1302. I24D:
  1303.     mov    al, byte ptr ds:[di]
  1304.     cmp    al, '$'
  1305.     jnz    I24Da
  1306.     ret
  1307.  
  1308. I24Da:
  1309.     push    di
  1310.     mov    ah, 0EH
  1311.     int    10H
  1312.     pop    di
  1313.     inc    di
  1314.     jmp    I24D
  1315.  
  1316. I24_Display    endp
  1317.  
  1318. ;
  1319. ;  Start of overwrite area for environment.  Align on a paragraph
  1320. ;
  1321. ;  Also the XMS driver functions used by SH3.C live here
  1322. ;
  1323.         ALIGN    16
  1324. Env_OWrite:
  1325.  
  1326. ;
  1327. ; XMS INTERFACE
  1328. ;
  1329. ; Get Version number.  Return the release number in AX
  1330. ;
  1331.  
  1332. _SW_XMS_Gversion    proc    far
  1333.  
  1334.     push    bp            ; Save stack info
  1335.     mov    bp, sp
  1336.  
  1337.     xor    ax, ax
  1338.     call    cs:[_SW_XMS_Driver]
  1339.  
  1340.     mov    sp, bp
  1341.     pop    bp
  1342.     ret
  1343.  
  1344. _SW_XMS_Gversion    endp
  1345.  
  1346. ;
  1347. ; Allocate N kbytes.  Return the Handler in AX or -1 and error code in
  1348. ; errno.
  1349. ;
  1350. ; Size will be in bp + 6.
  1351. ;
  1352.  
  1353. _SW_XMS_Allocate    proc    far
  1354.  
  1355.     push    bp            ; Save stack info
  1356.     mov    bp, sp
  1357.  
  1358.     mov    dx, word ptr ss:[bp + 6]
  1359.     mov    ah, 09H
  1360.     call    cs:[_SW_XMS_Driver]
  1361.     or    ax, ax
  1362.     jnz    $SW_A1
  1363.  
  1364. ;
  1365. ; Allocate Failed - return error code
  1366. ;
  1367.     xor    ax, ax
  1368.     dec    ax
  1369.     xor    bh, bh
  1370.     mov    word ptr ds:_errno, bx    ; Save error code
  1371.     jmp    $SW_A2
  1372.  
  1373. ;
  1374. ; Allocate OK - return handler
  1375. ;
  1376.  
  1377. $SW_A1:
  1378.     mov    ax, dx
  1379.  
  1380. $SW_A2:
  1381.     mov    sp, bp
  1382.     pop    bp
  1383.     ret
  1384.  
  1385. _SW_XMS_Allocate    endp
  1386.  
  1387. ;
  1388. ; Release handler.  Return 0 or error code.
  1389. ;
  1390. ; Handler will be in bp + 6.
  1391. ;
  1392.  
  1393. _SW_XMS_Free         proc    far
  1394.  
  1395.     push    bp            ; Save stack info
  1396.     mov    bp, sp
  1397.  
  1398.     mov    dx, word ptr ss:[bp + 6]
  1399.     mov    ah, 0AH
  1400.     call    cs:[_SW_XMS_Driver]
  1401.     or    ax, ax
  1402.     jnz    $SW_F1
  1403. ;
  1404. ; Free Failed - return error code
  1405. ;
  1406.     mov    al, bl
  1407.     jmp    $SW_F2
  1408.  
  1409. ;
  1410. ; Free OK - return zero
  1411. ;
  1412. $SW_F1:
  1413.     xor    ax, ax
  1414.  
  1415. $SW_F2:
  1416.     mov    sp, bp
  1417.     pop    bp
  1418.     ret
  1419.  
  1420. _SW_XMS_Free         endp
  1421.  
  1422. ;
  1423. ; Get available memory space.  Return 0 if failed.
  1424. ;
  1425.  
  1426.  
  1427. _SW_XMS_Available    proc    far
  1428.  
  1429.     push    bp            ; Save stack info
  1430.     mov    bp, sp
  1431.     mov    ah, 08H
  1432.     call    cs:[_SW_XMS_Driver]
  1433.     or    bl, bl
  1434.     jz    $SW_Avail1
  1435.  
  1436. ;
  1437. ; Free Failed - return zero
  1438. ;
  1439.     xor    ax, ax
  1440.  
  1441. $SW_Avail1:
  1442.     mov    sp, bp
  1443.     pop    bp
  1444.     ret
  1445.  
  1446. _SW_XMS_Available    endp
  1447.  
  1448. ;
  1449. ; Read Keyboard via interrupt 21 function 6.
  1450. ; Return Keyboard code in AL and SHIFT status in AH
  1451. ;
  1452.  
  1453. _Read_Keyboard    proc    far
  1454.  
  1455.     push    bp
  1456.     mov    bp, sp
  1457.     push    ds            ; Save the C registers
  1458.     push    es
  1459.     push    si
  1460.     push    di
  1461.  
  1462. ReadK1:
  1463.     mov    ah, 6            ; Read the keyboard
  1464.     mov    dl, 0ffH
  1465.     int    021H
  1466.     jnz    ReadK2
  1467.  
  1468. ; If polling is enabled - poll first
  1469.  
  1470.     cmp    byte ptr cs:_SW_poll, 0    ; polling?
  1471.     jz    ReadK1            ; NO
  1472.  
  1473.     mov    AX, 01000H        ; Release timeslice.
  1474.     int    015H
  1475.     jmp    ReadK1
  1476.  
  1477. ; Got a character - Check for interrupt
  1478.  
  1479. ReadK2:
  1480.     push    ax
  1481.     mov    ah, 02H            ; Get the SHIFT status
  1482.     int    16H
  1483.     mov    bx, ax    
  1484.     pop    ax
  1485.     mov    ah, bl            ; Save it in AH.
  1486.  
  1487.     cmp    al, 03H            ; Check for interrupt
  1488.     jne    ReadK3
  1489.  
  1490.     mov    ax, 02H            ; Yes - raise a sigint!
  1491.     push    ax
  1492.     call    _raise
  1493.     add    sp, 2
  1494.  
  1495. ReadK3:
  1496.     pop    di            ; Restore stack
  1497.     pop    si
  1498.     pop    es
  1499.     pop    ds
  1500.     mov    sp, bp
  1501.     pop    bp
  1502.     ret    
  1503.  
  1504. _Read_Keyboard    endp
  1505.  
  1506. ;
  1507. ; Main Entry point.  This part can be overwritten by the environment
  1508. ;
  1509.  
  1510. _SA_spawn    proc    far
  1511.  
  1512.     push    bp
  1513.     mov    bp, sp
  1514.  
  1515. ;
  1516. ; Entry Offsets
  1517. ;
  1518. ;    Environment      = 6
  1519. ;
  1520.  
  1521.     mov    word ptr cs:S_di, di        ; Save registers
  1522.     mov    word ptr cs:S_si, si
  1523.     mov    word ptr cs:S_ds, ds
  1524.  
  1525. ;
  1526. ; Save the length of the current MCB block;
  1527. ;
  1528.  
  1529.     mov    ax, word ptr ds:__psp
  1530.     dec    ax
  1531.     mov    word ptr cs:N_mcb, ax        ; Save MCB address for swap out
  1532.  
  1533. ; Calculate low mem start for extended memory
  1534.  
  1535.     mov    bx, ax                ; Save copy
  1536.     mov    cl, 4                ; mult low order by 16
  1537.     shl    ax, cl
  1538.     mov    word ptr cs:SW_LMstart, ax    ; Save low order
  1539.     mov    cl, 12                ; div by 16 ** 3
  1540.     shr    bx, cl
  1541.     mov    byte ptr cs:SW_LMstart + 2, bl    ; Save low order
  1542.  
  1543. ;
  1544. ; Set up Environment segment in execute structure
  1545. ;
  1546.  
  1547.     mov    bx, cs
  1548.     mov    ax, offset Env_OWrite
  1549.     mov    cl, 4
  1550.     shr    ax, cl
  1551.     add    ax, bx
  1552.     mov    word ptr cs:exec_env, ax    ; Save Env seg.
  1553.  
  1554. ;
  1555. ; Set up rest of execute structure
  1556. ;
  1557.  
  1558.     mov    word ptr cs:exec_cseg, cs    ; Command line address
  1559.     mov    word ptr cs:exec_f1seg, cs    ; FCB 1 address
  1560.     mov    word ptr cs:exec_f2seg, cs    ; FCB 2 address
  1561.  
  1562. ;
  1563. ; Generate the FCBs
  1564. ;
  1565.  
  1566.     mov    ax, cs        ; Set up segments
  1567.     mov    ds, ax
  1568.     mov    es, ax
  1569.  
  1570.     mov    ax, 02901H    ; Set up FCB interrupt
  1571.     mov    si, offset _cmd_line + 1
  1572.     mov    di, offset FCB1    ; FCB 1;
  1573.  
  1574.     int    021H        ; Execute the interrupt
  1575.  
  1576.     mov    ax, cs        ; Set up segment
  1577.     mov    es, ax
  1578.  
  1579.     mov    ax, 02901H    ; Reset AX cause errors are ignored
  1580.     mov    di, offset FCB2    ; FCB 2;
  1581.  
  1582.     int    021H        ; Execute the interrupt
  1583.  
  1584. ;
  1585. ; Copy out to the swap file
  1586. ;
  1587.  
  1588.     mov    bx, word ptr cs:_SW_fp        ; Load file handler
  1589.     mov    si, word ptr cs:_SW_Blocks    ; Load Number of blocks to read
  1590.     mov    ax, word ptr cs:N_mcb        ; Load the start address
  1591.  
  1592. ;
  1593. ;  Check for Partial write on disk swap file
  1594. ;
  1595.  
  1596.     cmp    word ptr cs: _SW_Mode, 1    ; Partial disk write ?
  1597.     jnz    SPart_Write
  1598.     cmp    word ptr cs: _SW_Pwrite, 0
  1599.     jz    SPart_Write
  1600.  
  1601.     mov    si, word ptr cs:_SW_SBlocks    ; Load Number of blocks to read
  1602.     mov    ax, word ptr cs:_etext        ; Load the start address
  1603.  
  1604. SPart_Write:
  1605.     push    ax
  1606.  
  1607. ; load up extended memory GDT for destination
  1608.  
  1609.     mov    ax, word ptr cs:_SW_EMstart
  1610.     mov    dl, byte ptr cs:_SW_EMstart + 2
  1611.     call    $GDT_dest_load
  1612.  
  1613. ;
  1614. ; set up DS register with start of start copy
  1615. ;
  1616.  
  1617.     pop    ax
  1618.     mov    ds, ax
  1619.     mov    ax, word ptr cs:SW_LMstart     ; Load Full start address
  1620.     mov    dl, byte ptr cs:SW_LMstart + 2
  1621.     call    $GDT_src_load
  1622.  
  1623. ;
  1624. ; Check for end of copy - BX contains the file handler for disk write
  1625. ;
  1626.  
  1627. $Write_loop:
  1628.     or    si, si
  1629.     jnz    $Write_L1
  1630.     jmp    $Write_Complete
  1631.  
  1632. ; OK - Copy next 0x4000 bytes - switch on device
  1633.  
  1634. $Write_L1:
  1635.     mov    ax, word ptr cs: _SW_Mode
  1636.     dec    ax
  1637.     jz    $W_disk
  1638.     dec    ax
  1639.     jnz    $Write_L2
  1640.     jmp    $W_extend
  1641. $Write_L2:
  1642.     dec    ax
  1643.     jnz    $W_xms
  1644.     jmp    $W_expand
  1645.  
  1646. ;
  1647. ; Write to XMS driver.  In this case, we do one write and let the driver
  1648. ; sort out the blocking
  1649. ;
  1650. $W_xms:
  1651.     xor    ax, ax
  1652.     mov    word ptr cs:XMS_SHandle, ax    ; Source - normal memory
  1653.     mov    word ptr cs:XMS_DHandle, bx    ; Dest - XMS
  1654.  
  1655.     mov    word ptr cs:XMS_Doffset, ax    ; Dest offset - zero
  1656.     mov    word ptr cs:XMS_Doffset + 2, ax
  1657.  
  1658.     mov    word ptr cs:XMS_Soffset, ax    ; Source offset DS:0
  1659.     mov    ax, ds
  1660.     mov    word ptr cs:XMS_Soffset + 2, ax
  1661.  
  1662. ;
  1663. ; Set up number of bytes SW_Block * 16 * 1024
  1664. ;
  1665.  
  1666.     mov    ax, si
  1667.     mov    dx, si
  1668.     mov    cl, 14
  1669.     shl    ax, cl
  1670.     mov    cl, 2
  1671.     shr    dx, cl
  1672.     mov    word ptr cs:XMS_Length, ax    ; Load number of bytes
  1673.     mov    word ptr cs:XMS_Length + 2, dx
  1674.  
  1675.     mov    ah, 0BH                ; Set up parameters
  1676.     mov    dx, cs
  1677.     mov    ds, dx
  1678.     mov    si, offset XMS_DIF
  1679.     call    cs:[_SW_XMS_Driver]
  1680.     or    ax, ax
  1681.     jnz     $Write_Complete
  1682.  
  1683. ; XMS error - abort
  1684.     
  1685.     mov    ah, bl
  1686.     jmp    $Write_error
  1687.  
  1688. ;
  1689. ; Write to disk
  1690. ;
  1691. $W_disk:
  1692.     call    $Write_disk
  1693.  
  1694. ; Increment counter
  1695.  
  1696. $Write_Incr:
  1697.     dec    si            ; Decrement block count
  1698.     mov    ax, ds            ; Increment offset
  1699.     add    ax, 0400H
  1700.     mov    ds, ax
  1701.     jmp    $Write_loop
  1702.  
  1703. ; Write to extended memory
  1704.  
  1705. $W_extend:
  1706.     call    $Write_extend
  1707.     jc    $Write_error        ; NO - abort
  1708.  
  1709.     dec    si            ; Decrement block count
  1710.     call    $Inc_Extend
  1711.     jmp    $Write_loop
  1712.  
  1713. ; Write to expanded memory
  1714. ;    BX - handler
  1715. ;    SI - count
  1716. ;    DS - source segment
  1717. ;
  1718. $W_expand:
  1719.     call    $map_ems_page        ; Map in the current EMS page
  1720.     jnz    $Write_error
  1721.  
  1722.     push    ds            ; Save DS and SI
  1723.     push    si
  1724.     mov    es, word ptr cs:_SW_EMSFrame    ; Set Dest Seg
  1725.     xor    si, si            ; Clear start
  1726.     xor    di, di
  1727.     mov    cx, 02000H        ; move 16K
  1728.     pushf                ; Save direction flag
  1729.     cld
  1730.     rep movsw
  1731.     popf                ; Restore direction flag
  1732.     pop    si            ; And DS, SI
  1733.     pop    ds
  1734.     jmp    $Write_Incr        ; Increment DS and dec SI
  1735.  
  1736. ;
  1737. ; Error - abort.  The error code is in AH.
  1738. ;
  1739.  
  1740. $Write_error:
  1741.     mov    ds, word ptr cs:S_ds    ; Restore DS
  1742.     mov    al, ah
  1743.     xor    ah, ah
  1744.     mov    word ptr ds:_errno, ax    ; Save error code
  1745.  
  1746. $Write_Error1:
  1747.     mov    ax, 0FFFEH
  1748.     jmp    $SA_spawn_Exit        ; Exit
  1749.  
  1750. ;
  1751. ; Swap file is now written, set up environment.  If this was a partial
  1752. ; write, we need to write the first 4K.
  1753. ;
  1754.  
  1755. $Write_Complete:
  1756.     cmp    word ptr cs: _SW_Mode, 1    ; Partial disk write ?
  1757.     jnz    S1Part_Write
  1758.     cmp    word ptr cs: _SW_Pwrite, 0
  1759.     jz    S1Part_Write
  1760.  
  1761.     mov    ax, 04200H            ; Set seek
  1762.     xor    dx, dx
  1763.     xor    cx, cx
  1764.     int    021H
  1765.     jnc    $Write_C1            ; Abort - swap file error
  1766.     jmp    $Map_error
  1767.  
  1768. $Write_C1:
  1769.     mov    ax, word ptr cs:N_mcb        ; Load the start address
  1770.     mov    ds, ax
  1771.     call    $Write_disk
  1772.  
  1773. ;
  1774. ; Go to the no-overwrite part.
  1775. ;
  1776.  
  1777. S1Part_Write:
  1778.     jmp    SA_spawn1
  1779. _SA_spawn    endp
  1780.  
  1781. ;
  1782. ; WRITE DISK FUNCTION
  1783. ;
  1784. ;    BX - file handler
  1785. ;    SI - Block count
  1786. ;    DS - Output data segement
  1787. ;
  1788.  
  1789. $Write_disk    proc    near
  1790.  
  1791.     mov    ax, 04000H        ; Set up to write
  1792.     mov    cx, ax            ; Load count
  1793.     xor    dx, dx            ; Clear start address
  1794.     push    bx            ; Save FP
  1795.     push    si            ; Save count and Data Segment
  1796.  
  1797.     int    021H            ; Write the data
  1798.  
  1799.     pop    si            ; Restore Regs
  1800.     pop    bx
  1801.     jnc    $Write_disk1        ; NO error - continue
  1802.  
  1803. ;
  1804. ; Error - abort
  1805. ;
  1806.     mov    ds, word ptr cs:S_ds    ; Restore DS
  1807.     mov    ah, al
  1808.     call    far ptr __maperror    ; Map the error
  1809.     jmp    $Write_Error1
  1810.  
  1811. ; Check for 16K write
  1812.  
  1813. $Write_disk1:
  1814.     cmp    ax, 04000H
  1815.     jnz    $Write_disk2
  1816.     ret
  1817.  
  1818. $Write_disk2:
  1819.     mov    ax,01c1cH        ; Set disk full
  1820.     jmp    $Write_error        ; NO - abort
  1821.  
  1822. $Write_disk    endp
  1823.  
  1824. ;
  1825. ; END OF SWAPPER
  1826. ;
  1827.  
  1828. SH0_TEXT    ends
  1829.         end
  1830.